home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
cmln0285.arc
/
ARGPAR.H
< prev
next >
Wrap
Text File
|
1986-02-27
|
41KB
|
1,318 lines
ARGPAR.H
by Alexander Abacus
February 1985 issue
/* argparse.h: @(#) macros for parsing command arguments. */
/* by Alexander B. Abacus */
/* Computer Language BBS file name: ARGPAR.H */
/* This file is formatted for readability and may not be used with */
/* all C compilers. For more portable version see ARGPARSE.H */
#if defined Hargparse
/* #endfile -- this file already included */
#else ! defined Hargparse /* first inclusion */
# define Hargparse /* and really include this file */
# ifdef COMMENT
/*
/* Macros defined in this file can be used to parse command line
/* as it is passed to the main program. Macro MAIN
/* can be used to produce the header of the function "main()".
/* Other macros should be used within the body of the function
/* main(). Macros ArgBEGIN(), ArgLOOP, and ArgEND must be used to
/* sandwich in the other macros.
/*
/* Command arguments can be positional or key letter arguments.
/* Key letter arguments start with a trigger character. Any
/* character can be specified as trigger character.
/* The default trigger character is '-'.
/*
/* Key letter arguments can be defined as either flag or text
/* arguments.
/*
/* Flag argument consists of a single key letter that
/* follows the trigger character. No text is expected after the
/* flag key letter. If any text follows a flag key letter without
/* a white space it is interpreted as additional key letters.
/* If any text follows a flag key letter after a white space
/* it is interpreted as another argument. Several flag key letters
/* may follow one trigger character.
/*
/* Text argument consists of a single key letter immediately
/* following a trigger character and followed by text either
/* immediately or after a white space.
/*
/* Positional arguments can be processed either after all
/* key letter arguments have been processed, or all arguments
/* can be processed in order, intermixing positional arguments
/* with key arguments. Double trigger character can be used
/* to signal the end of key letter arguments. Another mode
/* is provided, but not recommended, in which the first
/* positional argument terminates key letter arguments.
/*
/*
/* For both Flag and Text arguments two macros exist:
/* one that Sets a variable and another that Calls a user
/* defined function.
/*
/* Following flags are predefined and can not be redefined:
/* '?' Output tutorial information to stderr.
/* '!' Output debugging information to stderr.
/* '-' (i.e. trigger character) end of key letter arguments.
/*
/*
/* Macros:
/*
/* @(#) ArgTutor( ... ) -- used internally.
/* Print tutorial message from string array 'tutorial'
/* to stderr and exit abnormally.
/*
/* @(#) MAIN()
/* Defines header for function main(argc, argv, envp).
/*
/* @(#) ArgMAIN is same as ArgBEGIN(argc, argv)
/*
/* @(#) ArgBEGIN( ArgumentCountVariable, ArgumentVector )
/* Begins sandwich that parses command arguments.
/* Macros described before ArgLOOP are optional.
/* If present, they must be coded between ArgBEGIN
/* and ArgLOOP. Those macros override provided defaults.
/* Each of them should be coded only once, if at all.
/* Macros described between ArgLOOP and ArgEND should
/* also be coded between ArgLOOP and ArgEND.
/* One of those macros must be coded for each key letter
/* argument.
/*
/* @(#) ArgTrigger( TriggerCharacter )
/* TriggerCharacter is used to recognize key letter arguments.
/* Default is '-'.
/*
/* @(#) ArgDescription( DescriptionStringArray )
/* Provides text to be printed after an error is detected
/* while parsing arguments.
/* char * tutorial[] = { 'Command', 'summary', 0 };
/*
/* @(#) ArgKeyLeading
/* If this macro is coded key arguments must precede positional
/* arguments. After the first positional argument is recognized,
/* all following arguments are treated as positional.
/* This mode is not recommended. It is provided just for the
/* sake of completeness (many programs parse arguments this way).
/*
/* @(#) ArgPosCall( FunctionName )
/* FunctionName is called for each positional argument.
/* If positional arguments are to be processed after all
/* key letter arguments, this macro should be left out.
/* It defaults to the dummy function "argPos()"
/* defined in this file. Otherwise a function
/* should be defined as:
/* char * functionName( keyCharacter, textString )
/* char keyCharacter; /* Always contains '\0'. */
/* char * textString; /* Points to positional argument. */
/* { ... }
/*
/* @(#) ArgMin( MinPositionals )
/* MinPositionals is minimum number of positional arguments.
/* If this macro is not coded, the check is not performed.
/*
/* @(#) ArgMax( MaxPositionals )
/* MaxPositionals is maximum number of positional arguments.
/* If this macro is not coded, the check is not performed.
/*
/* @(#) ArgLOOP
/* This macro marks the end of default override macros.
/* It is followed by macros describing key letter arguments.
/*
/* @(#) ArgFlagSet( KeyLetter, CounterVariable )
/* Increment counter for this flag.
/* CounterVariable should be initially zero.
/*
/* @(#) ArgTextSet( KeyLetter, PointerVariable )
/* Set pointer to text argument.
/*
/* @(#) ArgFlagCall( KeyLetter, FunctionName )
/* @(#) ArgTextCall( KeyLetter, FunctionName )
/* Call user defined function to process key letter argument.
/* Function must be defined as:
/* char * functionName( keyCharacter, textString )
/* char keyCharacter; /* Key letter. */
/* char * textString; /* NULL for flag, or points to text. */
/* { ... }
/* If pointer returned by this function is not NULL,
/* the tutorial message will be printed to stderr
/* and abnormal exit will be taken.
/*
/* @(#) ArgEND
/* Ends sandwich that parses command arguments.
/*
/* Example of use: See end of this file.
*/
# endif COMMENT
/*[ A.1 ] Include for debugging. */
# if ! defined FILE
# include <stdio.h>
# endif ! defined FILE
# if ! defined Hdebug
# include "debug.h"
# endif ! defined Hdebug
/*[ A.2 ] Output tutorial information. */
# define ArgTutor(A_Tutorial) \
{ \
char ** line; \
for ( (line = A_Tutorial); ((*line) != (char *) 0); (++line) ) \
{ \
StdMsg \
( stderr \
, " %s" \
, *line \
); \
} \
ABEND(1); \
} \
/*[ B.1 ] Standard heading for main(). */
# define MAIN() \
main(argc, argv, envp) \
int argc; \
char *argv[]; \
char *envp[]; \
/*[ B.2 ] Begin sandwich, parse, process positional arguments. */
# define ArgMAIN ArgBEGIN(argc, argv)
# define ArgBEGIN(A_argc, A_argv) \
{ /* Begin block with local variables. Ends with ArgEND. */ \
struct \
{ \
int argc; \
int * ptrArgCount; \
char ** argVector; \
char * (*ptrFunction) (); \
int minPositionals; \
int maxPositionals; \
int keysLeading; \
char keyTrigger; \
char ** tutorial; \
\
char * description[2]; \
int argIndex; \
int charIndex; \
int nextPositional; \
int noOfPositionals; \
int keysTerminated; /* ON/OFF switch */ \
char * textPointer; \
char * keyPointer; \
} a0; \
\
a0.ptrArgCount = &(A_argc); \
a0.argc = *a0.ptrArgCount; \
a0.argVector = (A_argv); \
a0.minPositionals = -1; \
a0.maxPositionals = -1; \
a0.ptrFunction = argPos; \
a0.keysLeading = 0; \
a0.keyTrigger = '-'; \
a0.tutorial = & a0.description[0]; \
a0.description[0] = "Description of arguments is not provided.\n"; \
a0.description[1] = (char *) 0; \
/*[ B.3 ] Optional macros to override defaults. */
#define ArgMin(A_Min) a0.minPositionals = (A_Min);
#define ArgMax(A_Max) a0.maxPositionals = (A_Max);
#define ArgPosCall(A_Function) a0.ptrFunction = (A_Function);
#define ArgKeyLeading a0.keysLeading = 1;
#define ArgTrigger(A_Trigger) a0.keyTrigger = (A_Trigger);
#define ArgDescription(A_Text) a0.tutorial = (A_Text);
/*[ B.4 ] Begining of argument loop. */
#define ArgLOOP \
a0.keysTerminated = 0; \
a0.nextPositional = 1; \
a0.argIndex = 1; \
\
if ( ( a0.argVector[1][0] == a0.keyTrigger ) \
&& ( a0.argVector[1][1] == '!' ) ) \
{ \
a0.textPointer = & a0.argVector[1][1]; \
DEBUGIN \
( \
/* if not followed by characters, debug all levels */ \
if ( (* (a0.textPointer + 1)) == '\0' ) debug[0] = (char) 127; \
\
/* if followed by characters, select debugging levels */ \
while ( (* ++a0.textPointer) != '\0' ) \
{ /* for all characters following -! */ \
if ((* a0.textPointer) < 128) ++debug[* a0.textPointer]; \
} /* for all characters following -! */ \
) /* DEBUGIN */ \
DEBUGOUT \
( \
StdMsg \
( stderr \
, " Compiled without debugging code. Option -! ineffective.\n" \
); \
) /* DEBUGOUT */ \
++a0.argIndex; \
} \
\
for ( (a0.argIndex); (a0.argIndex < a0.argc); (++a0.argIndex) ) \
{ /* for all arguments */ \
if ( ( a0.argVector[a0.argIndex][0] != a0.keyTrigger ) \
|| ( a0.keysTerminated != 0 ) \
|| ( a0.argVector[a0.argIndex][1] == '\0' ) ) \
{ /* not a key: bubble up positional arguments */ \
DEBUG \
( 3, \
StdMsg \
( stderr \
, "Positional argument %d \"%s\".\n" \
, a0.nextPositional \
, a0.argVector[a0.argIndex] \
); \
) /* DEBUG */ \
if \
( ( a0.maxPositionals >= 0 ) \
&& ( a0.nextPositional > a0.maxPositionals ) \
) \
{ /* if(too many positionals) */ \
StdMsg \
( stderr \
, " Stop. Maximum %d positional arguments, excess at \"%s\".\n" \
, a0.maxPositionals \
, a0.argVector[a0.argIndex] \
); \
ArgTutor( a0.tutorial ); \
} /* if(too many positionals) */ \
a0.keysTerminated |= a0.keysLeading; \
a0.argVector[a0.nextPositional] = a0.argVector[a0.argIndex]; \
(void) (*a0.ptrFunction) ( '\0', a0.argVector[a0.nextPositional] ); \
++a0.nextPositional; \
} \
else /* it is a key */ \
{ \
DEBUG \
( 3, \
StdMsg \
( stderr \
, "Key argument \"%s\".\n" \
, a0.argVector[a0.argIndex] \
); \
) /* DEBUG */ \
a0.charIndex = 0; \
a0.keyPointer = & a0.argVector[a0.argIndex][0]; \
do \
{ /* for all characters in an argument */ \
++a0.charIndex; \
++a0.keyPointer; \
DEBUG \
( 3, \
StdMsg \
( stderr \
, "Key letter \'%c\'.\n" \
, *a0.keyPointer \
); \
) /* DEBUG */ \
if ( a0.keyPointer[0] == a0.keyTrigger ) \
{ \
if ( a0.charIndex != 1 ) \
{ \
StdMsg \
( stderr \
, " Stop. Terminator of keys must be alone: \"%s\".\n" \
, a0.argVector[a0.argIndex] \
); \
ArgTutor( a0.tutorial ); \
} \
if ( a0.keyPointer[1] != '\0' ) \
{ \
StdMsg \
( stderr \
, " Stop. Terminator of keys followed by: \"%s\".\n" \
, a0.argVector[a0.argIndex] \
); \
ArgTutor( a0.tutorial ); \
} \
a0.keysTerminated = 1; \
} \
else \
{ \
switch ( a0.keyPointer[0] ) \
{ \
case '?': \
ArgTutor( a0.tutorial ); \
EXIT( a0.argc != 2); \
# ifdef COMMENT
/*
/* The previous and the following macro form the sandwich into which
/* macro calls defining key letter arguments will be inserted.
/* Comunication between macros making up the sandwich is through
/* the members of the structure declared in the previous macro.
/* The structure is local to the sandwich.
*/
# endif COMMENT
/*[ B.5 ] End sandwich, verify number of positional arguments. */
# define ArgEND \
default: \
StdMsg \
( stderr \
, " Stop. Key letter \'%c\' rejected.\n" \
, *a0.keyPointer \
); \
ArgTutor( a0.tutorial ); \
break; \
} /* switch */ \
} /* if not double trigger */ \
} /* for all characters in argument */ \
while ( a0.keyPointer != (char *) 0 ); \
} /* if key or not a key */ \
} /* for all arguments */ \
\
a0.noOfPositionals = a0.nextPositional - 1; \
\
if \
( ( a0.minPositionals >= 0 ) \
&& ( a0.noOfPositionals < a0.minPositionals ) \
) \
{ /* if(too few positionals) */ \
StdMsg \
( stderr \
, " Stop. Minimum %d positional arguments, %d supplied.\n" \
, a0.minPositionals \
, a0.noOfPositionals \
); \
ArgTutor( a0.tutorial ); \
} /* if(too few positionals) */ \
\
(* a0.ptrArgCount) = a0.noOfPositionals; \
} /* End block begun with ArgBEGIN. */ \
/*[ C.1 ] Key-letter flag argument, deferred processing. */
# define ArgFlagSet(A_KeyLetter, A_FlagCounter) \
case A_KeyLetter: \
++A_FlagCounter; \
DEBUG \
( 3, \
StdMsg \
( stderr \
, "Flag \'%c\' accepted, occurance number %d.\n" \
, *a0.keyPointer \
, A_FlagCounter \
); \
) /* DEBUG */ \
break; \
/*[ C.2 ] Key-letter flag argument, immediate processing. */
# define ArgFlagCall(A_KeyLetter, A_FlagFunction) \
case A_KeyLetter: \
DEBUG \
( 3, \
StdMsg \
( stderr \
, "Flag \'%c\' accepted, function \"%s()\" called.\n" \
, *a0.keyPointer \
, "A_FlagFunction" \
); \
) /* DEBUG */ \
if (A_FlagFunction ( *a0.keyPointer, (char *) 0 ) != (char *) 0 ) \
{ \
ArgTutor( a0.tutorial ); \
} \
break; \
/*[ C.3 ] Key-letter text argument, deferred processing. */
# define ArgTextSet(A_KeyLetter, A_TextPointer) \
case A_KeyLetter: \
if ( A_TextPointer != (char *) 0 ) \
{ \
StdMsg \
( stderr \
, " Stop. Repeated key-letter '%c' with text.\n" \
, A_KeyLetter \
); \
ArgTutor( a0.tutorial ); \
} \
argText \
( & A_TextPointer \
, & a0.keyPointer \
, & a0.argIndex \
, a0.charIndex \
, a0.keyTrigger \
, a0.argc \
, a0.argVector \
, a0.tutorial \
); \
break; \
/*[ C.4 ] Key-letter text argument, immediate processing. */
# define ArgTextCall(A_KeyLetter, A_TextFunction) \
case A_KeyLetter: \
argText \
( & a0.textPointer \
, & a0.keyPointer \
, & a0.argIndex \
, a0.charIndex \
, a0.keyTrigger \
, a0.argc \
, a0.argVector \
, a0.tutorial \
); \
if(A_TextFunction ( A_KeyLetter, a0.textPointer ) != (char *) 0 ) \
{ \
ArgTutor( a0.tutorial ); \
} \
break; \
/*[ D.1 ] Dummy function for processing positional arguments. */
static
char * argPos( a_keyChar, a_argString )
char a_keyChar;
char * a_argString;
{
START ( '0', "argPos", 0 )
RETURN ( (char) 0 );
}
/*[ D.2 ] Function common for key-letter text arguments. */
static Void argText
( a_textPointer
, a_keyPointer
, a_argIndex
, a_charIndex
, a_keyTrigger
, a_argc
, a_argv
, a_tutorial
)
char ** a_textPointer;
char ** a_keyPointer;
int * a_argIndex;
int a_charIndex;
char a_keyTrigger;
int a_argc;
char * a_argv[];
char * a_tutorial[];
{ /* argText() */
START('0', "argText", "(string) \"%s\"")
if ( a_charIndex != 1 )
{
StdMsg
( stderr
, " Stop. Key letter with text must stand alone: \"%s\".\n"
, a_argv[*a_argIndex]
);
ArgTutor( & a_tutorial[0] );
}
else if ( ( (*a_keyPointer)[1]) != '\0' )
{ /* text following key letter without a separating white space */
(*a_textPointer) = (char *) & (*a_keyPointer)[1];
}
else /* text must be in the following argument */
{
++(*a_argIndex);
if ( ((*a_argIndex) >= a_argc)
|| (a_keyTrigger == *a_argv[*a_argIndex]) )
{ /* text is missing */
StdMsg
( stderr
, " Stop. Text not found after key letter \"%s\".\n"
, *a_keyPointer
);
--(*a_argIndex);
ArgTutor( & a_tutorial[0] );
}
else
{
(*a_textPointer) = (char *) a_argv[*a_argIndex];
} /* endif */
} /* endif */
DEBUG
( 3,
StdMsg
( stderr
, "Key letter \'%c\' with text \"%s\".\n"
, ** a_keyPointer
, * a_textPointer
);
) /* DEBUG */
(*a_keyPointer) = (char *) 0;
RETURN ( Nothing );
} /* argText() */
/* --------------------------------------------------------------- */
# if defined DriverH
# undef DriverH
/* T.1: Test driver for this include. */
#define Storage static
#include "debug.h"
static char * tutorial[] =
{
"Expected arguments are: file1 file2 \n",
" file1 is the source, \n",
" file2 is the target. \n",
0
};
main(argCount, argVector)
int argCount;
char * argVector[];
{
int f_flag = 0;
char *t_text = (char *) 0;
START('m', "main", 0)
ArgBEGIN (argCount, argVector)
ArgMin (1)
ArgMax (2)
ArgDescription(tutorial)
ArgLOOP
ArgFlagSet ('f', f_flag)
ArgTextSet ('t', t_text)
ArgFlagCall ('F', argPos)
ArgTextCall ('T', argPos)
ArgEND
EXIT (0);
} /* main */
# endif DriverH
#endif Hargparse
/* argparse.h: End of file. */
*********************************************************************
Other files of importance
by Alexander Abacus
ARGBEGIN.H
/* argbegin.h: @(#) Begin argument parsing sandwich, see argparse.h */
/* by Alexander B. Abacus */
#ifndef ArgCount
#define ArgCount argc
#endif
#ifndef ArgVector
#define ArgVector argv
#endif
{ /* Begin block with local variables. Ends with argend.h */
struct
{
char ** tutorial;
char ** argVector;
char * description[2];
char * textPointer;
char * keyPointer;
char * (*ptrFunction) ();
int * ptrArgCount;
int argc;
int minPositionals;
int maxPositionals;
int keysLeading;
int argIndex;
int charIndex;
int nextPositional;
int noOfPositionals;
int keysTerminated; /* ON/OFF switch */
char keyTrigger;
} a0;
a0.ptrArgCount = &(ArgCount);
a0.argc = *a0.ptrArgCount;
a0.argVector = (ArgVector);
a0.minPositionals = -1;
a0.maxPositionals = -1;
a0.ptrFunction = argPos;
a0.keysLeading = 0;
a0.keyTrigger = '-';
a0.tutorial = & a0.description[0];
a0.description[0] = "Description of arguments is not provided.\n";
a0.description[1] = (char *) 0;
/* argbegin.h: End of file. */
ARGEND.H
/* argend.h: @(#) End sandwichbegun with argbegin.h, see argparse.h */
/* by Alexander B. Abacus */
default:
fprintf
( stderr
, " Stop. Key letter \'%c\' rejected.\n"
, *a0.keyPointer
);
ArgTutor( a0.tutorial );
break;
} /* switch */
} /* if not double trigger */
} /* for all characters in argument */
while ( a0.keyPointer != (char *) 0 );
} /* if key or not a key */
} /* for all arguments */
a0.noOfPositionals = a0.nextPositional - 1;
if
( ( a0.minPositionals >= 0 )
&& ( a0.noOfPositionals < a0.minPositionals )
)
{ /* if(too few positionals) */
fprintf
( stderr
, " Stop. Minimum %d positional arguments, %d supplied.\n"
, a0.minPositionals
, a0.noOfPositionals
);
ArgTutor( a0.tutorial );
} /* if(too few positionals) */
(* a0.ptrArgCount) = a0.noOfPositionals;
} /* End block begun with argbegin.h */
/* argend.h: End of file. */
ARGLOOP.H
/* argloop.h: @(#) Begining of argument loop, see argparse.h */
/* by Alexander B. Abacus */
a0.keysTerminated = 0;
a0.nextPositional = 1;
a0.argIndex = 1;
if ( ( a0.argVector[1][0] == a0.keyTrigger )
&& ( a0.argVector[1][1] == '!' ) )
{
a0.textPointer = & a0.argVector[1][1];
#ifdef Debug
/* if not followed by characters, debug all levels */
if ( (* (a0.textPointer + 1)) == '\0' ) debug[0] = (char) 127;
/* if followed by characters, select debugging levels */
while ( (* ++a0.textPointer) != '\0' )
{ /* for all characters following -! */
if ((* a0.textPointer) < 128) ++debug[* a0.textPointer];
} /* for all characters following -! */
#else ! defined Debug
fprintf
( stderr
, " Compiled without debugging code. Option -! ineffective.\n"
);
#endif Debug
++a0.argIndex;
}
for ( (a0.argIndex); (a0.argIndex < a0.argc); (++a0.argIndex) )
{ /* for all arguments */
#ifdef DriverH
fprintf ( stderr, "Word %d \"%s\".\n", a0.argIndex, a0.argVector[a0.argIndex] );
#endif DriverH
if ( ( a0.argVector[a0.argIndex][0] != a0.keyTrigger )
|| ( a0.keysTerminated != 0 )
|| ( a0.argVector[a0.argIndex][1] == '\0' ) )
{ /* not a key: bubble up positional arguments */
if
( ( a0.maxPositionals >= 0 )
&& ( a0.nextPositional > a0.maxPositionals )
)
{ /* if(too many positionals) */
fprintf
( stderr
, " Stop. Maximum %d positional arguments, excess at \"%s\".\n"
, a0.maxPositionals
, a0.argVector[a0.argIndex]
);
ArgTutor( a0.tutorial );
} /* if(too many positionals) */
a0.keysTerminated |= a0.keysLeading;
a0.argVector[a0.nextPositional] = a0.argVector[a0.argIndex];
/* (void) */ (*a0.ptrFunction) ( '\0', a0.argVector[a0.nextPositional] );
++a0.nextPositional;
}
else /* it is a key */
{
a0.charIndex = 0;
a0.keyPointer = & a0.argVector[a0.argIndex][0];
do
{ /* for all characters in an argument */
++a0.charIndex;
++a0.keyPointer;
if ( (*a0.keyPointer) == '\0' ) { break; } /* from do ... while */
#ifdef DriverH
fprintf( stderr, "Remaining argument: \"%s\".\n", a0.keyPointer );
#endif DriverH
if ( a0.keyPointer[0] == a0.keyTrigger )
{
if ( a0.charIndex != 1 )
{
fprintf
( stderr
, " Stop. Terminator of keys must be alone: \"%s\".\n"
, a0.argVector[a0.argIndex]
);
ArgTutor( a0.tutorial );
}
if ( a0.keyPointer[1] != '\0' )
{
fprintf
( stderr
, " Stop. Terminator of keys followed by: \"%s\".\n"
, a0.argVector[a0.argIndex]
);
ArgTutor( a0.tutorial );
}
a0.keysTerminated = 1;
}
else
{
switch ( a0.keyPointer[0] )
{
case '?':
ArgTutor( a0.tutorial );
exit( a0.argc != 2);
/* argloop.h: End of file. */
ARGPAR.1
Listing 1
to
Macros Special Series on C Macros
February 1985
>> Simplified argument parsing, positional and flag <<
#define ArgBEGIN(A_argc, A_argv) \
{ /* Begin block with local variables. Ends with ArgEND. */ \
struct \
{ int argc, *ptrArgCount; \
char ** argVector; \
char * (*ptrFunction) (); \
char keyTrigger, *keyPointer; \
int argIndex, charIndex, nextPositional, keysTerminated; \
} a0; \
a0.ptrArgCount = &(A_argc); a0.argVector = (A_argv); \
a0.argc = *a0.ptrArgCount; a0.keyTrigger = '-'; \
a0.ptrFunction = argPos;
#define ArgPosCall(A_Function) a0.ptrFunction = (A_Function);
#define ArgTrigger(A_Trigger) a0.keyTrigger = (A_Trigger);
#define ArgLOOP \
a0.keysTerminated = 0; a0.nextPositional = 1; \
for ( (a0.argIndex = 1); (a0.argIndex < a0.argc); (++a0.argIndex) ) \
{ /* for all arguments */ \
if ( ( a0.argVector[a0.argIndex][0] != a0.keyTrigger ) \
|| ( a0.keysTerminated != 0 ) \
|| ( a0.argVector[a0.argIndex][1] == '\0' ) ) \
{ /* not a key: bubble up positional arguments */ \
a0.argVector[a0.nextPositional] = a0.argVector[a0.argIndex]; \
(void) (*a0.ptrFunction) ( '\0', a0.argVector[a0.nextPositional] ); \
++a0.nextPositional; \
} \
else /* it is a key */ \
{ \
for \
( (a0.charIndex = 1, a0.keyPointer = & a0.argVector[a0.argIndex][1]) \
; ( ( a0.keyPointer != (char *) 0 ) \
&& ( (*a0.keyPointer) != '\0' ) \
) \
; (++a0.charIndex, ++a0.keyPointer) \
) \
{ /* for all characters in an argument */ \
switch ( a0.keyPointer[0] ) \
{
#define ArgFlagSet(A_KeyLetter, A_FlagCounter) \
case A_KeyLetter: ++A_FlagCounter; break;
#define ArgFlagCall(A_KeyLetter, A_Function) \
case A_KeyLetter: (A_Function)( *a0.keyPointer, 0 ); break;
#define ArgEND \
default: \
(void) fprintf \è ( stderr \
, " Stop. Key letter \'%c\' rejected.\n" \
, *a0.keyPointer \
); \
exit (1); \
} /* switch */ \
} /* for all characters in argument */ \
} /* if key or not a key */ \
} /* for all arguments */ \
(* a0.ptrArgCount) = a0.nextPositional - 1; \
} /* End block begun with ArgBEGIN. */ \
static char * argPos( a_keyChar, a_argString )
char a_keyChar, *a_argString;
{ return ( (char *) 0 ); }
/* --------------------------------------------------------------- */
#if defined DriverH
#include <stdio.h>
void main(argCount, argVector)
int argCount;
char * argVector[];
{
int f_flag = 0;
ArgBEGIN (argCount, argVector)
ArgPosCall (argPos)
ArgTrigger ('-')
ArgLOOP
ArgFlagSet ('f', f_flag)
ArgFlagCall ('F', argPos)
ArgEND
exit (0);
} /* main */
#endif DriverH
ARGPARSE.H
/* argparse.h: @(#) macros for parsing command arguments. */
/* by Alexander B. Abacus */
/* Computer Language BBS file name ARGPARSE.H */
/* This and related files make a more portable version of ARGPAR.H */
/* related files: argparse.use, argbegin.h, argloop.h, argend.h */
#ifdef Hargsmall
/* #endfile -- this file already included */
#else ! defined Hargparse /* first inclusion */
#define Hargsmall
/* and really include this file */
/*[ A.1 ] Required include. */
#ifndef FILE
#include <stdio.h>
#endif ! defined FILE
/*[ A.2 ] Output tutorial information. */
/* void */ ArgTutor(line)
char ** line;
{
for ( (line); ((*line) != (char *) 0); (++line) )
{
fprintf
( stderr
, " %s"
, *line
);
}
exit(1);
}
/*[ A.3 ] Dummy function for processing positional arguments. */
static
char * argPos( a_keyChar, a_argString )
char a_keyChar;
char * a_argString;
{
#ifdef DriverH
fprintf ( stderr, "Argument" );
if ( a_keyChar != '\0' )
{
fprintf ( stderr, " key-letter \'%c\'", a_keyChar );
}
if ( a_argString != (char *) 0 )
{
fprintf ( stderr, " text \"%s\"", a_argString );
}
fprintf ( stderr, ".\n" );
#endif DriverH
return ( (char *) 0 );
}
/*[ B.1 ] Standard heading for main(). */
#define MAIN() main(argc, argv, envp) int argc; char *argv[]; char *envp[];
/*[ B.2 ] Optional macros to override defaults. */
#define ArgMin(A_Min) a0.minPositionals = (A_Min);
#define ArgMax(A_Max) a0.maxPositionals = (A_Max);
#define ArgPosCall(A_Function) a0.ptrFunction = (A_Function);
#define ArgKeyLeading a0.keysLeading = 1;
#define ArgTrigger(A_Trigger) a0.keyTrigger = (A_Trigger);
#define ArgDescription(A_Text) a0.tutorial = (A_Text);
/*[ C.1 ] Key-letter flag argument, deferred processing. */
#define ArgFlagSet(A_KeyLetter, A_FlagCounter) case A_KeyLetter: ++A_FlagCounter; break;
/*[ C.2 ] Key-letter flag argument, immediate processing. */
#define ArgFlagCall(A_KeyLetter, A_FlagFunction) case A_KeyLetter: if (A_FlagFunction ( *a0.keyPointer, (char *) 0 ) != (char *) 0 ) { ArgTutor( a0.tutorial ); } break;
/*[ C.3 ] Key-letter text argument, deferred processing. */
#define ArgTextSet(A_KeyLetter, A_TextPointer) \
case A_KeyLetter: \
argText \
( & A_TextPointer \
, & a0.keyPointer \
, & a0.argIndex \
, a0.charIndex \
, a0.keyTrigger \
, a0.argc \
, a0.argVector \
, a0.tutorial \
, A_KeyLetter \
, 0 \
); \
break;
/*[ C.4 ] Key-letter text argument, immediate processing. */
#define ArgTextCall(A_KeyLetter, A_TextFunction) \
case A_KeyLetter: \
argText \
( & a0.textPointer \
, & a0.keyPointer \
, & a0.argIndex \
, a0.charIndex \
, a0.keyTrigger \
, a0.argc \
, a0.argVector \
, a0.tutorial \
, A_KeyLetter \
, A_TextFunction \
); \
break;
/*[ D.2 ] Function common for key-letter text arguments. */
static /* void */ argText
( a_textPointer
, a_keyPointer
, a_argIndex
, a_charIndex
, a_keyTrigger
, a_argc
, a_argv
, a_tutorial
, a_keyLetter
, a_textFunction
)
char ** a_textPointer;
char ** a_keyPointer;
int * a_argIndex;
int a_charIndex;
char a_keyTrigger;
int a_argc;
char * a_argv[];
char * a_tutorial[];
char a_keyLetter;
char * (*a_textFunction) ();
{ /* argText() */
if ( a_textFunction == 0 )
{ /* ArgTextSet */
if ( (* a_textPointer) != (char *) 0 )
{ /* second occurance of this key letter */
fprintf
( stderr
, " Stop. Repeated key-letter '%c' with text.\n"
, a_keyLetter
);
ArgTutor( a_tutorial );
} /* second occurance of this key letter */
} /* ArgTextSet */
if ( a_charIndex != 1 )
{
fprintf
( stderr
, " Stop. Key letter with text must stand alone: \"%s\".\n"
, a_argv[*a_argIndex]
);
ArgTutor( & a_tutorial[0] );
}
else if ( ( (*a_keyPointer)[1]) != '\0' )
{ /* text following key letter without a separating white space */
(*a_textPointer) = (char *) & (*a_keyPointer)[1];
}
else /* text must be in the following argument */
{
++(*a_argIndex);
if ( ((*a_argIndex) >= a_argc)
|| (a_keyTrigger == *a_argv[*a_argIndex]) )
{ /* text is missing */
fprintf
( stderr
, " Stop. Text not found after key letter \"%s\".\n"
, *a_keyPointer
);
--(*a_argIndex);
ArgTutor( & a_tutorial[0] );
}
else
{
(*a_textPointer) = (char *) a_argv[*a_argIndex];
} /* endif */
} /* endif */
if ( a_textFunction != 0 )
{ /* ArgTextCall */
if((*a_textFunction) ( a_keyLetter, (* a_textPointer) ) != (char *) 0 )
{
ArgTutor( a_tutorial );
}
} /* ArgTextCall */
(*a_keyPointer) = (char *) 0; /* to skip to next element of argv */
return;
} /* argText() */
/* --------------------------------------------------------------- */
#ifdef DriverH
/* T.1: Test driver for this include. */
static char * tutorial[] =
{
"Expected arguments are: file1 file2 \n",
" file1 is the source, \n",
" file2 is the target. \n",
0
};
main(argCount, argVector)
int argCount;
char * argVector[];
{
int f_flag = 0;
char *t_text = (char *) 0;
#define ArgCount argCount
#define ArgVector argVector
#include "argbegin.h"
ArgMin (1)
ArgMax (2)
ArgDescription(tutorial)
#include "argloop.h"
ArgFlagSet ('f', f_flag)
ArgFlagCall ('F', argPos)
ArgTextSet ('t', t_text)
ArgTextCall ('T', argPos)
#include "argend.h"
fprintf ( stderr, "Flag counter: %d.\n", f_flag );
if ( t_text != (char *) 0 )
{
fprintf ( stderr, "Text: \"%s\".\n", t_text );
}
exit (0);
} /* main */
#endif DriverH
#endif Hargsmall
/* argparse.h: End of file. */
ARGPARSE.USE
#ifdef COMMENT
/*
/* This file describes the use of files: argparse.h, argbegin.h, argloop.h,
/* and argend.h. Those files make a more portable implementation of the
/* macros defined and described in the file argpar.h.
/* The most important difference is that macros ArgBEGIN(), ArgLOOP, and
/* ArgEND have been replaced with include files argbegin.h, argloop.h, and
/* argend.h. Text of those macros exceeds buffer sizes of C preprocessors
/* on micro-computers.
/*
/* Macros described in this file can be used to parse command line
/* as it is passed to the main program. Macro MAIN
/* can be used to produce the header of the function "main()".
/* Other macros should be used within the body of the function
/* main(). Includes argbegin.h, argloop.h, and argend.h must be used to
/* sandwich in the macros.
/*
/* Command arguments can be positional or key letter arguments.
/* Key letter arguments start with a trigger character. Any
/* character can be specified as trigger character.
/* The default trigger character is '-'.
/*
/* Key letter arguments can be defined as either flag or text
/* arguments.
/*
/* Flag argument consists of a single key letter that
/* follows the trigger character. No text is expected after the
/* flag key letter. If any text follows a flag key letter without
/* a white space it is interpreted as additional key letters.
/* If any text follows a flag key letter after a white space
/* it is interpreted as another argument. Several flag key letters
/* may follow one trigger character.
/*
/* Text argument consists of a single key letter immediately
/* following a trigger character and followed by text either
/* immediately or after a white space.
/*
/* Positional arguments can be processed either after all
/* key letter arguments have been processed, or all arguments
/* can be processed in order, intermixing positional arguments
/* with key arguments. Double trigger character can be used
/* to signal the end of key letter arguments. Another mode
/* is provided, but not recommended, in which the first
/* positional argument terminates key letter arguments.
/*
/*
/* For both Flag and Text arguments two macros exist:
/* one that Sets a variable and another that Calls a user
/* defined function.
/*
/* Following flags are predefined and can not be redefined:
/* '?' Output tutorial information to stderr.
/* '!' Output debugging information to stderr.
/* '-' (i.e. trigger character) end of key letter arguments.
/*
/*
/* Macros:
/*
/* @(#) ArgTutor( ... ) -- used internally.
/* Print tutorial message from string array 'tutorial'
/* to stderr and exit abnormally.
/*
/* @(#) MAIN()
/* Defines header for function main(argc, argv, envp).
/*
/* @(#) #define ArgCount argc
/* @(#) #define ArgVector argv
/* @(#) #include 'argbegin.h'
/* Begins sandwich that parses command arguments.
/* Macros described before argloop.h are optional.
/* If present, they must be coded between argbegin.h
/* and argloop.h. Those macros override provided defaults.
/* Each of them should be coded only once, if at all.
/* Macros described between argloop.h and argend.h should
/* also be coded between argloop.h and argend.h.
/* One of those macros must be coded for each key letter
/* argument.
/*
/* @(#) ArgTrigger( TriggerCharacter )
/* TriggerCharacter is used to recognize key letter arguments.
/* Default is '-'.
/*
/* @(#) ArgDescription( DescriptionStringArray )
/* Provides text to be printed after an error is detected
/* while parsing arguments.
/* char * tutorial[] = { 'Command', 'summary', 0 };
/*
/* @(#) ArgKeyLeading
/* If this macro is coded key arguments must precede positional
/* arguments. After the first positional argument is recognized,
/* all following arguments are treated as positional.
/* This mode is not recommended. It is provided just for the
/* sake of completeness (many programs parse arguments this way).
/*
/* @(#) ArgPosCall( FunctionName )
/* FunctionName is called for each positional argument.
/* If positional arguments are to be processed after all
/* key letter arguments, this macro should be left out.
/* It defaults to the dummy function "argPos()"
/* defined in this file. Otherwise a function
/* should be defined as:
/* char * functionName( keyCharacter, textString )
/* char keyCharacter; /* Always contains '\0'. */
/* char * textString; /* Points to positional argument. */
/* { ... }
/*
/* @(#) ArgMin( MinPositionals )
/* MinPositionals is minimum number of positional arguments.
/* If this macro is not coded, the check is not performed.
/*
/* @(#) ArgMax( MaxPositionals )
/* MaxPositionals is maximum number of positional arguments.
/* If this macro is not coded, the check is not performed.
/*
/* @(#) #include 'argloop.h'
/* This macro marks the end of default override macros.
/* It is followed by macros describing key letter arguments.
/*
/* @(#) ArgFlagSet( KeyLetter, CounterVariable )
/* Increment counter for this flag.
/* CounterVariable should be initially zero.
/*
/* @(#) ArgTextSet( KeyLetter, PointerVariable )
/* Set pointer to text argument.
/*
/* @(#) ArgFlagCall( KeyLetter, FunctionName )
/* @(#) ArgTextCall( KeyLetter, FunctionName )
/* Call user defined function to process key letter argument.
/* Function must be defined as:
/* char * functionName( keyCharacter, textString )
/* char keyCharacter; /* Key letter. */
/* char * textString; /* NULL for flag, or points to text. */
/* { ... }
/* If pointer returned by this function is not NULL,
/* the tutorial message will be printed to stderr
/* and abnormal exit will be taken.
/*
/* @(#) #include 'argend.h'
/* Ends sandwich that parses command arguments.
/*
/* Example of use: See end of file argparse.h.
*/
#endif COMMENT